package com.neu.wms.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * @author DAIJUNQIANG
 * @version 1.0
 * @description 做相关的Security的配置:此处为基本配置，我们注释掉了@Configuration和@EnableWebSecurity注解，因为我们要使用自定义的Security配置类
 * @date 2023/6/30 15:28
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailsService userDetailsService;

	@Autowired
	private LogoutSuccessHandler logoutSuccessHandler;

	@Autowired
	private AccessDeniedHandler accessDeniedHandler;

	@Bean
	LoginAuthenticationSuccessHandler successHandler() {
		return new LoginAuthenticationSuccessHandler();
	}

	@Bean
	LoginAuthenticationFailureHandler failureHandler() {
		return new LoginAuthenticationFailureHandler();
	}

	@Bean
	JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
		return new JwtAuthenticationTokenFilter();
	}

	@Bean
	LoginFilter loginFilter() throws Exception {
		LoginFilter loginFilter = new LoginFilter();
		loginFilter.setAuthenticationManager(authenticationManager());
		loginFilter.setAuthenticationSuccessHandler(successHandler());
		loginFilter.setAuthenticationFailureHandler(failureHandler());
		return loginFilter;
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	/**
	 * 配置登录页面
	 *
	 * @param httpSecurity http请求
	 * @throws Exception 异常
	 */
	@Override
	protected void configure(HttpSecurity httpSecurity) throws Exception {
		// CRSF禁用，不使用session
		httpSecurity.csrf().disable();
		//允许跨域
		httpSecurity.cors();
		// 基于token，所以不需要session
		httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
		// 过滤请求，‘/users/login’不能使用.anonymous(),否则登录成功再点登录时一直提示403
		httpSecurity.authorizeRequests()
				.antMatchers("/users/login").permitAll()
				//权限校验：我们只对用户的操作
				//这里有一个小bug /users/** 和users/**  拦截的路径不一样导致权限校验失败
				//.antMatchers(HttpMethod.DELETE,"/users/**").hasAuthority("system:user:delete")
				//.antMatchers(HttpMethod.DELETE,"/users/**").hasRole("管理员")
				.anyRequest().authenticated();

		// 添加loginFilter,在UsernamePasswordAuthenticationFilter过滤器所在位置添加
		httpSecurity.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
		// 添加jwt过滤器 在UsernamePasswordAuthenticationFilter过滤器所在位置之前添加
		httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);

		httpSecurity.logout().logoutSuccessHandler(logoutSuccessHandler);//退出成功后的处理类
		httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), LogoutFilter.class);

		httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler);//无权访问的拦截器处理403的拦截器


	}




	/**
	 * 配置认证管理器
	 *
	 * @param auth 身份认证管理器的构造器对象
	 * @throws Exception 异常
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {


		//TODO 和老师的不一样，做一个标记
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}
}
